home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1995 October
/
EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso
/
Aminet
/
comm
/
tcp
/
amitcptelnetf.lha
/
amitcp_telnet+ftp
/
telnet
/
sys_bsd.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-13
|
13KB
|
644 lines
/*
* Copyright (c) 1988, 1990 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted provided
* that: (1) source distributions retain this entire copyright notice and
* comment, and (2) distributions including binaries display the following
* acknowledgement: ``This product includes software developed by the
* University of California, Berkeley and its contributors'' in the
* documentation or other materials provided with the distribution and in
* all advertising materials mentioning features or use of this software.
* Neither the name of the University nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef lint
static char sccsid[] = "@(#)sys_bsd.c 5.1 (Berkeley) 9/14/90";
#endif /* not lint */
/*
* The following routines try to encapsulate what is system dependent
* (at least between 4.x and dos) which is used in telnet.c.
*/
#include <fcntl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <string.h>
#include <sys/socket.h>
#ifdef AMI_TCP
#include <bsdsocket.h>
#define ioctl IoctlSocket
#else
#include <ss/socket.h>
#endif
#include <signal.h>
#include <errno.h>
#include <arpa/telnet.h>
#ifdef __SASC
#include <ios1.h>
#endif
#include "ring.h"
#include "fdset.h"
#include "defines.h"
#include "externs.h"
#include "types.h"
#define SIG_FUNC_RET int
int
tout, /* Output file descriptor */
tin, /* Input file descriptor */
net;
#ifndef AMI_TCP
struct tchars otc = { 0 }, ntc = { 0 };
struct sgttyb ottyb = { 0 }, nttyb = { 0 };
#endif
int olmode = 0;
# define cfgetispeed(ptr) (ptr)->sg_ispeed
# define cfgetospeed(ptr) (ptr)->sg_ospeed
# define old_tc ottyb
static fd_set ibits, obits, xbits;
//void (*signal())()
//{ return;
//}
init_sys()
{
tout = fileno(stdout);
tin = fileno(stdin);
FD_ZERO(&ibits);
FD_ZERO(&obits);
FD_ZERO(&xbits);
errno = 0;
}
TerminalWrite(buf, n)
char *buf;
int n;
{
return write(tout, buf, n);
}
TerminalRead(buf, n)
char *buf;
int n;
{
return read(tin, buf, n);
}
/*
*
*/
int
TerminalAutoFlush()
{
return 1;
}
/*
* Flush output to the terminal
*/
void
TerminalFlushOutput()
{
fflush(stdout);
}
void
TerminalSaveState()
{
return;
}
cc_t *
tcval(func)
register int func;
{
switch(func) {
case SLC_SYNCH:
case SLC_BRK:
case SLC_EOR:
default:
return((cc_t *)0);
}
}
void
TerminalDefaultChars()
{
return;
}
#ifdef notdef
void
TerminalRestoreState()
{
}
#endif
/*
* TerminalNewMode - set up terminal to a specific mode.
* MODE_ECHO: do local terminal echo
* MODE_FLOW: do local flow control
* MODE_TRAPSIG: do local mapping to TELNET IAC sequences
* MODE_EDIT: do local line editing
*
* Command mode:
* MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
* local echo
* local editing
* local xon/xoff
* local signal mapping
*
* Linemode:
* local/no editing
* Both Linemode and Single Character mode:
* local/remote echo
* local/no xon/xoff
* local/no signal mapping
*/
void
TerminalNewMode(f)
register int f;
{
static int prevmode = 0;
#ifndef USE_TERMIO
#ifdef __SASC
int ami_cbreak = 0;
#else
struct sgttyb sb;
#endif
#endif
int lmode;
int onoff;
int old;
globalmode = f&~MODE_FORCE;
if (prevmode == f)
return;
/*
* Write any outstanding data before switching modes
* ttyflush() returns 0 only when there is no more data
* left to write out, it returns -1 if it couldn't do
* anything at all, otherwise it returns 1 + the number
* of characters left to write.
#ifndef USE_TERMIO
* We would really like ask the kernel to wait for the output
* to drain, like we can do with the TCSADRAIN, but we don't have
* that option. The only ioctl that waits for the output to
* drain, TIOCSETP, also flushes the input queue, which is NOT
* what we want (TIOCSETP is like TCSADFLUSH).
#endif
*/
old = ttyflush(SYNCHing|flushout);
if (old < 0 || old > 1) {
do {
/*
* Wait for data to drain, then flush again.
*/
old = ttyflush(SYNCHing|flushout);
} while (old < 0 || old > 1);
}
old = prevmode;
prevmode = f&~MODE_FORCE;
lmode = olmode;
if (f&MODE_ECHO) {
#ifndef __SASC
sb.sg_flags |= ECHO;
#endif
} else {
#ifndef __SASC
sb.sg_flags &= ~ECHO;
#endif
}
if ((f&MODE_FLOW) == 0) {
}
if ((f&MODE_TRAPSIG) == 0) {
localchars = 0;
} else {
localchars = 1;
}
if (f&MODE_EDIT) {
#ifdef __SASC
ami_cbreak = 0;
#else
sb.sg_flags &= ~CBREAK;
sb.sg_flags &= ~RAW;
sb.sg_flags |= CRMOD;
#endif
} else {
#ifdef __SASC
ami_cbreak = 1;
#else
sb.sg_flags |= CBREAK;
sb.sg_flags |= RAW;
if (f&MODE_ECHO)
sb.sg_flags |= CRMOD;
else
sb.sg_flags &= ~CRMOD;
#endif
}
if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) {
}
if (f&MODE_SOFT_TAB) {
#ifndef __SASC
sb.sg_flags |= XTABS;
#endif
} else {
#ifndef __SASC
sb.sg_flags &= ~XTABS;
#endif
}
if (f&MODE_LIT_ECHO) {
} else {
}
if (f == -1) {
onoff = 0;
} else {
onoff = 1;
}
if (f != -1) {
/*
* We don't want to process ^Y here. It's just another
* character that we'll pass on to the back end. It has
* to process it because it will be processed when the
* user attempts to read it, not when we send it.
*/
} else {
lmode = olmode;
}
#ifdef __SASC
SetMode(chkufb(0)->ufbfh,ami_cbreak);
#else
SetMode(_devtab[0].fd,(sb.sg_flags & CBREAK) ? 1L : 0L);
#endif
ioctl(tin, FIONBIO, (char *)&onoff);
ioctl(tout, FIONBIO, (char *)&onoff);
}
int
TerminalWindowSize(rows, cols)
long *rows, *cols;
{
return 0;
}
int
NetClose(fd)
int fd;
{
#ifdef AMI_TCP
return CloseSocket(fd);
#else
return s_close(fd);
#endif
}
void
NetNonblockingIO(fd, onoff)
int
fd,
onoff;
{
ioctl(fd, FIONBIO, (char *)&onoff);
}
/*
* Various signal handling routines.
*/
/* ARGSUSED */
static SIG_FUNC_RET
deadpeer(sig)
int sig;
{
setcommandmode();
longjmp(peerdied, -1);
}
/* ARGSUSED */
static SIG_FUNC_RET
intr(sig)
int sig;
{
if (localchars) {
intp();
return;
}
setcommandmode();
longjmp(toplevel, -1);
}
/* ARGSUSED */
static SIG_FUNC_RET
intr2(sig)
int sig;
{
if (localchars) {
sendabort();
return;
}
}
#ifdef SIGTSTP
/* ARGSUSED */
static SIG_FUNC_RET
susp(sig)
int sig;
{
if (localchars)
sendsusp();
}
#endif
#ifdef SIGWINCH
/* ARGSUSED */
static SIG_FUNC_RET
sendwin(sig)
int sig;
{
if (connected) {
sendnaws();
}
}
#endif
#ifdef SIGINFO
/* ARGSUSED */
static SIG_FUNC_RET
ayt(sig)
int sig;
{
if (connected)
sendayt();
else
ayt_status();
}
#endif
void
sys_telnet_init()
{
setconnmode(0);
NetNonblockingIO(net, 1);
#if defined(SO_OOBINLINE)
{ int one=1;
#ifdef AMI_TCP
if (setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &one,sizeof(one)) == -1)
#else
if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, &one,sizeof(one)) == -1)
#endif
{
perror("SetSockOpt");
}
}
#endif /* defined(SO_OOBINLINE) */
}
/*
* Process rings -
*
* This routine tries to fill up/empty our various rings.
*
* The parameter specifies whether this is a poll operation,
* or a block-until-something-happens operation.
*
* The return value is 1 if something happened, 0 if not.
*/
int
process_rings(netin, netout, netex, ttyin, ttyout, poll)
int poll; /* If 0, then block until something to do */
{
register int c;
/* One wants to be a bit careful about setting returnValue
* to one, since a one implies we did some useful work,
* and therefore probably won't be called to block next
* time (TN3270 mode only).
*/
int returnValue = 0;
static struct timeval TimeValue = { 0 };
static struct timeval Quickie = {0L,20000L};
extern long bytesin;
if (netout) {
FD_SET(net, &obits);
}
if (netin) {
FD_SET(net, &ibits);
}
if (netex) {
FD_SET(net, &xbits);
}
if ((c = select(16, &ibits, &obits, &xbits,
(poll == 0)? (struct timeval *)&Quickie : &TimeValue)) < 0) {
if (c == -1) {
/*
* we can get EINTR if we are in line mode,
* and the user does an escape (TSTP), or
* some other signal generator.
*/
if (errno == EINTR) {
return 0;
}
/* I don't like this, does it ever happen? */
printf("sleep(5) from telnet, after select\r\n");
sleep(5);
}
return 0;
}
/*
* Any urgent data?
*/
if (FD_ISSET(net, &xbits)) {
FD_CLR(net, &xbits);
SYNCHing = 1;
(void) ttyflush(1); /* flush already enqueued data */
}
/*
* Something to read from the network...
*/
if (FD_ISSET(net, &ibits)) {
int canread;
FD_CLR(net, &ibits);
canread = ring_empty_consecutive(&netiring);
#if !defined(SO_OOBINLINE)
/*
* In 4.2 (and some early 4.3) systems, the
* OOB indication and data handling in the kernel
* is such that if two separate TCP Urgent requests
* come in, one byte of TCP data will be overlaid.
* This is fatal for Telnet, but we try to live
* with it.
*
* In addition, in 4.2 (and...), a special protocol
* is needed to pick up the TCP Urgent data in
* the correct sequence.
*
* What we do is: if we think we are in urgent
* mode, we look to see if we are "at the mark".
* If we are, we do an OOB receive. If we run
* this twice, we will do the OOB receive twice,
* but the second will fail, since the second
* time we were "at the mark", but there wasn't
* any data there (the kernel doesn't reset
* "at the mark" until we do a normal read).
* Once we've read the OOB data, we go ahead
* and do normal reads.
*
* There is also another problem, which is that
* since the OOB byte we read doesn't put us
* out of OOB state, and since that byte is most
* likely the TELNET DM (data mark), we would
* stay in the TELNET SYNCH (SYNCHing) state.
* So, clocks to the rescue. If we've "just"
* received a DM, then we test for the
* presence of OOB data when the receive OOB
* fails (and AFTER we did the normal mode read
* to clear "at the mark").
*/
if (SYNCHing) {
int atmark;
static int bogus_oob = 0, first = 1;
s_ioctl(net, SIOCATMARK, (char *)&atmark);
if (atmark) {
c = recv(net, netiring.supply, canread, MSG_OOB);
if ((c == -1) && (errno == EINVAL)) {
c = recv(net, netiring.supply, canread, 0);
if (clocks.didnetreceive < clocks.gotDM) {
SYNCHing = stilloob(net);
}
} else if (first && c > 0) {
/*
* Bogosity check. Systems based on 4.2BSD
* do not return an error if you do a second
* recv(MSG_OOB). So, we do one. If it
* succeeds and returns exactly the same
* data, then assume that we are running
* on a broken system and set the bogus_oob
* flag. (If the data was different, then
* we probably got some valid new data, so
* increment the count...)
*/
int i;
i = recv(net, netiring.supply + c, canread - c, MSG_OOB);
if (i == c &&
bcmp(netiring.supply, netiring.supply + c, i) == 0) {
bogus_oob = 1;
first = 0;
} else if (i < 0) {
bogus_oob = 0;
first = 0;
} else
c += i;
}
if (bogus_oob && c > 0) {
int i;
/*
* Bogosity. We have to do the read
* to clear the atmark to get out of
* an infinate loop.
*/
i = read(net, netiring.supply + c, canread - c);
if (i > 0)
c += i;
}
} else {
c = recv(net, netiring.supply, canread, 0);
}
} else {
c = recv(net, netiring.supply, canread, 0);
}
settimer(didnetreceive);
#else /* !defined(SO_OOBINLINE) */
c = recv(net, netiring.supply, canread, 0);
#endif /* !defined(SO_OOBINLINE) */
if (c < 0 && errno == EWOULDBLOCK) {
c = 0;
} else if (c <= 0) {
return -1;
}
if (netdata) {
Dump('<', netiring.supply, c);
}
if (c)
bytesin+=c;
ring_supplied(&netiring, c);
returnValue = 1;
}
/*
* Something to read from the tty...
*/
#ifdef __SASC
if (WaitForChar(chkufb(0)->ufbfh,Quickie.tv_usec)) {
#else
if (WaitForChar(_devtab[0].fd,Quickie.tv_usec)) {
#endif
// FD_CLR(tin, &ibits);
c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
if (c < 0 && errno == EWOULDBLOCK) {
c = 0;
} else {
/* EOF detection for line mode!!!! */
if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
/* must be an EOF... */
#ifndef __SASC
*ttyiring.supply = termEofChar;
#endif
c = 1;
}
if (c <= 0) {
return -1;
}
ring_supplied(&ttyiring, c);
}
returnValue = 1; /* did something useful */
}
if (FD_ISSET(net, &obits)) {
FD_CLR(net, &obits);
returnValue |= netflush();
}
returnValue |= (ttyflush(SYNCHing|flushout) > 0);
return returnValue;
}